package com.etl.mongodb.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.data.mongodb.core.query.Criteria;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * 查询 匹配操作符 封装
 * <p>
 * User: Locker1995
 * Date: 2018-03-20
 * Time: 10:26 AM
 */
public class CriteriaUtil {

    protected static final int COMPARE_LTE = 1; //小于等于 lte

    protected static final int COMPARE_LT = 2;//小于 lt

    protected static final int COMPARE_GTE = 3;// 大于等于 gte

    protected static final int COMPARE_GT = 4;//大于 gt

    protected static final int COMPARE_NE = 5;//不等于 ne

    protected static final int COMPARE_EQ = 6;//等于 eq

    protected static final int COMPARE_IN = 7;// 存在于 in

    protected static final int COMPARE_NIN = 8;//不存在于 nin

    /**
     *
     * 匹配均忽略大小写
     *
     */
    protected static final int LEFT_MATCHING=9;//左匹配 不区分大小写

    protected static final int RIGHT_MATCHING=10;//右匹配 不区分大小写

    protected static final int ALL_MATCHING=11;//模糊匹配 不区分大小写

    protected static final String UNION_AND = "and";// 并查询

    protected static final String UNION_OR = "or";// 或查询

    /**
     * 获得一个mongodb Query Criteria条件对象
     *
     * @param str
     * @return
     */
    public static Criteria getQueryCriteria(String str) {
        //获得当前JsonStr的JsonObject
        JSONObject jsonObject = JSONObject.parseObject(str);
        //判断该JsonObject中是否含有 criterias属性
        if (jsonObject.containsKey("criterias")) {
            //creiterias 都是数组
            JSONArray jsonArray = jsonObject.getJSONArray("criterias");
            List<Criteria> criteriaList = new ArrayList<Criteria>();
            //初始化连接符
            String connector = null;
            for (int i = 0; i < jsonArray.size(); i++) {
                //当前遍历对象
                JSONObject current = jsonArray.getJSONObject(i);
                //判断这个subCreiteria 是什么类型
                if (!current.containsKey("column")) {
                    //没有column 这个字段说明要深度遍历
                    //返回一个最终的Criteria
                    Criteria criteria = getQueryCriteria(current.toString());
                    String currentNextOperation = current.getString("nextOperation");
                    if(null == connector){
                        connector = currentNextOperation;
                        criteriaList.add(criteria);
                    }else if(connector.equals(currentNextOperation)){
                        criteriaList.add(criteria);
                        continue;
                    }else {
                        //识别连接符 把之前的加上当前的在栈里的Criteria组合成一个Criteria
                        criteriaList.add(criteria);
                        //之前同类型的连接符对象出栈 组合成为一个新的Criteria
                        Criteria newCriteria = connectSameTypeCriteria(criteriaList,connector);
                        //清空栈
                        criteriaList.clear();
                        criteriaList.add(newCriteria);
                        //重新设置connector
                        connector = currentNextOperation;
                    }
                } else {
                    //如果有column 说明当前是最小的Criteria
                    Criteria criteria = getSubCriteria(current);
                    String currentNextOperation = current.getString("nextOperation");
                    if(null == connector){
                        connector = currentNextOperation;
                        criteriaList.add(criteria);
                    }else if(connector.equals(currentNextOperation)){
                        criteriaList.add(criteria);
                    }else {
                        //识别连接符 把之前的加上当前的在栈里的Criteria组合成一个Criteria
                        criteriaList.add(criteria);
                        //之前同类型的连接符对象出栈 组合成为一个新的Criteria
                        Criteria newCriteria = connectSameTypeCriteria(criteriaList,connector);
                        //清空栈
                        criteriaList.clear();
                        criteriaList.add(newCriteria);
                        //重新设置connector
                        connector = currentNextOperation;
                    }
                }
            }
            return criteriaList.size() == 1 ? criteriaList.get(0) : connectSameTypeCriteria(criteriaList,connector);
        } else {
            //否则则当前对象是一个最小的 Criterias;
            return getSubCriteria(jsonObject);
        }
    }

    /**
     * 得到一个最小结构的Criteria对象
     *
     * @param jsonObject
     * @return
     */
    protected static Criteria getSubCriteria(JSONObject jsonObject) {


        Criteria criteria = new Criteria();
        //获得比较符号
        int operation = jsonObject.getIntValue("operation");

        // 获得value
        String value = jsonObject.getString("value");

        //获得column
        String column = jsonObject.getString("column");

        switch (operation) {
            case CriteriaUtil.COMPARE_LTE:
                criteria.and(column).lte(value);
                break;
            case CriteriaUtil.COMPARE_LT:
                criteria.and(column).lt(value);
                break;
            case CriteriaUtil.COMPARE_GTE:
                criteria.and(column).gte(value);
                break;
            case CriteriaUtil.COMPARE_GT:
                criteria.and(column).gt(value);
                break;
            case CriteriaUtil.COMPARE_NE:
                criteria.and(column).ne(value);
                break;
            case CriteriaUtil.COMPARE_EQ:
                criteria.and(column).is(value);
                break;
            case CriteriaUtil.COMPARE_IN:
                criteria.and(column).in(value);
                break;
            case CriteriaUtil.COMPARE_NIN:
                criteria.and(column).nin(value);
                break;
            case CriteriaUtil.LEFT_MATCHING:
                Pattern pattern1 = Pattern.compile("^"+value+".*$", Pattern.CASE_INSENSITIVE);
                criteria.and(column).regex(pattern1);
                break;
            case CriteriaUtil.RIGHT_MATCHING:
                Pattern pattern2 = Pattern.compile("^.*"+value+"$", Pattern.CASE_INSENSITIVE);
                criteria.and(column).regex(pattern2);
                break;
            case CriteriaUtil.ALL_MATCHING:
                Pattern pattern3 = Pattern.compile("^.*"+value+".*$", Pattern.CASE_INSENSITIVE);
                criteria.and(column).regex(pattern3);
                break;
            default:
                System.out.println("匹配无果");
                break;
        }

        return criteria;
    }

    /**
     * 把同一个connector的Criteria 链接成为一个Criteria
     * @param sameList
     * @param connector
     * @return
     */
    protected static Criteria connectSameTypeCriteria(List<Criteria> sameList,String connector){
        Criteria newCriteria = new Criteria();
        if (UNION_AND.equals(connector))
            newCriteria.andOperator(sameList.toArray(new Criteria[sameList.size()]));
        if (UNION_OR.equals(connector))
            newCriteria.orOperator(sameList.toArray(new Criteria[sameList.size()]));
        return newCriteria;
    }

}
